package org.study.dsm.mybatisplus.controller;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Maps;
import com.zaxxer.hikari.HikariDataSource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.study.dsm.mybatisplus.config.*;
import org.study.dsm.mybatisplus.mapper.DataSourceInfoMapper;
import org.study.dsm.mybatisplus.mapper.UserMapper;
import org.study.dsm.mybatisplus.model.DataSourceInfo;
import org.study.dsm.mybatisplus.model.User;

import javax.sql.DataSource;
import java.sql.*;
import java.util.List;
import java.util.Map;

/**
 * 参考 https://blog.csdn.net/m0_48420795/article/details/126529465
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2024年04月27日
 */
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@RestController
public class DataSourceInfoController {
    private final UserMapper userMapper;
    private final DataSourceInfoMapper dataSourceInfoMapper;
    private final DynamicDataSource dynamicDataSource;

    @GetMapping("/add/{dsKey}")
    public DataSourceInfo addDataSourceInfo(@PathVariable("dsKey") String dsKey) {
        DataSourceInfo dataSourceInfo = dataSourceInfoMapper.selectOne(
                Wrappers.<DataSourceInfo>lambdaQuery()
                        .eq(DataSourceInfo::getDsKey, dsKey)
        );
        if (dataSourceInfo == null) {
            // 新增到数据库中
            dataSourceInfo = DataSourceInfo.builder()
                    .dsKey(dsKey)
                    .url("jdbc:mysql://localhost:3306/test_ds?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai")
                    .username("root")
                    .password("root")
                    .build();
            dataSourceInfoMapper.insert(dataSourceInfo);
            // 向dynamic-datasource中添加一个新的数据源
            dynamicDataSource.createDataSourceWithCheck(dataSourceInfo);
        }
        return dataSourceInfo;
    }

    @GetMapping("/update/{dsKey}")
    public DataSourceInfo updateDataSourceInfo(@PathVariable("dsKey") String dsKey) {
        DataSourceInfo dataSourceInfo = dataSourceInfoMapper.selectOne(
                Wrappers.<DataSourceInfo>lambdaQuery()
                        .eq(DataSourceInfo::getDsKey, dsKey)
        );
        if (dataSourceInfo != null) {
            // 先从dynamic-datasource删除原来的数据源
            dynamicDataSource.deleteDataSources(dsKey);
            // 再向dynamic-datasource中添加一个新的数据源
            dynamicDataSource.createDataSourceWithCheck(dataSourceInfo);
        }
        return null;
    }

    @GetMapping("/delete/{dsKey}")
    public Boolean deleteDataSourceInfo(@PathVariable("dsKey") String dsKey) {
        int deleted = dataSourceInfoMapper.delete(
                Wrappers.<DataSourceInfo>lambdaQuery()
                        .eq(DataSourceInfo::getDsKey, dsKey));
        if (deleted > 0) {
            // 从dynamic-datasource删除数据源
            dynamicDataSource.deleteDataSources(dsKey);
        }
        return Boolean.TRUE;
    }

    @GetMapping("/exists/{dsKey}")
    public Boolean existsDataSource(@PathVariable("dsKey") String dsKey) {
        return dynamicDataSource.existsDataSource(dsKey);
    }

    @GetMapping("/check/{dsKey}")
    public Boolean checkDataSource(@PathVariable("dsKey") String dsKey) {
        return dynamicDataSource.checkDataSource(dsKey);
    }

    @GetMapping("/list")
    public Map<String, Object> listDataSourceInfo() {
        Map<String, Object> result = Maps.newLinkedHashMap();
        // 数据库中的数据源信息
        List<DataSourceInfo> dataSourceInfoList = dataSourceInfoMapper.selectList(null);
        result.put("数据库中的数据源个数：", dataSourceInfoList.size());
        result.put("数据库中的数据源信息：", dataSourceInfoList);
        // dynamic-datasource中的数据源信息
        Map<Object, Object> objectObjectMap = dynamicDataSource.getDynamicTargetDataSources();
        result.put("dynamic-datasource中的数据源个数：", objectObjectMap.size());
        result.put("dynamic-datasource中的数据源名称：", objectObjectMap.keySet());
        return result;
    }

    @GetMapping("/test1/{dsKey}")
    public Map<String, Object> testDynamicDataSource1(@PathVariable("dsKey") String dsKey) {
        Map<String, Object> map = Maps.newLinkedHashMap();
        // 在主库中查询用户信息
        List<User> oldUserList = userMapper.selectList(null);
        map.put("oldUserList", oldUserList);
        oldUserList.forEach(user -> log.info("用户信息1：{}", JSON.toJSONString(user)));
        // 在从库中查询数据源信息
        DynamicDataSourceHolder.setDataSource(CommonConstant.SLAVE);
        DataSourceInfo dataSourceInfo = dataSourceInfoMapper.selectOne(
                Wrappers.<DataSourceInfo>lambdaQuery()
                        .eq(DataSourceInfo::getDsKey, dsKey)
        );
        log.info("数据源信息：{}", dataSourceInfo);
        map.put("dataSource", dataSourceInfo);
        if (dynamicDataSource.createDataSourceWithCheck(dataSourceInfo)) {
            // 设置当前线程数据源名称
            DynamicDataSourceHolder.setDataSource(dsKey);
            // 在新的数据源中查询用户信息
            List<User> newUserList = userMapper.selectList(null);
            newUserList.forEach(user -> log.info("用户信息2：{}", JSON.toJSONString(user)));
            map.put("newUserList", newUserList);
        }
        return map;
    }

    @GetMapping("/test2/{dsKey}")
    public Map<String, Object> testDynamicDataSource2(@PathVariable("dsKey") String dsKey) {
        Map<String, Object> map = Maps.newLinkedHashMap();
        map.put("dsKey", dsKey);
        map.put("online", Boolean.FALSE);
        Map<Object, Object> dataSourceMap = dynamicDataSource.getDynamicTargetDataSources();
        dataSourceMap.forEach((dsName, dynamicDataSource) -> {
            String poolType = null;
            if (dynamicDataSource instanceof DruidDataSource druidDataSource) {
                poolType = "Druid";
                try (Connection connection = druidDataSource.getConnection()) {

                } catch (SQLException ex) {
                }
            } else if (dynamicDataSource instanceof HikariDataSource hikariDataSource) {
                poolType = "Hikari";
                try (Connection connection = hikariDataSource.getConnection()) {

                } catch (SQLException ex) {
                }
            } else {
                log.warn("其他类型的数据库连接池");
            }
            log.info("当前数据源名称：{}，连接池类型：{}", dsName, poolType);
        });
        Object object = dynamicDataSource.getDynamicTargetDataSources().get(dsKey);
        if (object instanceof DataSource dataSource) {
            try (Connection connection = dataSource.getConnection();
                 PreparedStatement ps = connection.prepareStatement("SELECT 1");
                 ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    int testResult = rs.getInt(1);
                    log.info("数据库服务器检测，数据源名称：{}，结果：{}", dsKey, testResult);
                    map.put("online", Boolean.TRUE);
                }
            } catch (SQLException ex) {
                log.error("数据库服务器检测异常，数据源名称：{}", dsKey, ex);
                map.put("online", Boolean.FALSE);
                map.put("errorMsg", ex.getMessage());
            }
        }
        return map;
    }
}
